/*
 
 Copyright (C) 2009 Id Software, Inc.
 
 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2
 of the License, or (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 */

#import "wolf3dAppDelegate.h"
#import "EAGLView.h"
#import <AudioToolbox/AudioServices.h>
#include "../wolfiphone.h"
#include "../wolf/wolf_math.h"
#import "../koth.h"
#import "JWSound.h"
#import "JWAboutScreen.h"
#import "JWHelpScreen.h"
#import "JWConfigureControls.h"
#import "JWOpenFeintKeys.h"

#import "OpenFeint.h"
#import "OFAchievementService.h"
#import "OFHighScoreService.h"

@interface UIApplication (Private)

- (void)setSystemVolumeHUDEnabled:(BOOL)enabled forAudioCategory:(NSString *)category;
- (void)setSystemVolumeHUDEnabled:(BOOL)enabled;

@end


char iphoneDocDirectory[1024];
char iphoneAppDirectory[1024];


void SysIPhoneVibrate() {
	AudioServicesPlaySystemSound( kSystemSoundID_Vibrate );
}

@implementation wolf3dAppDelegate

@synthesize window;
@synthesize glView;

//- (void)applicationDidFinishLaunching:(UIApplication *)application
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
	menuState = IPM_MAIN;
	NSDictionary* settings = [NSDictionary dictionaryWithObjectsAndKeys:
							  [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft], OpenFeintSettingDashboardOrientation, nil];
	
	[OpenFeint initializeWithProductKey:JW_OPEN_FEINT_PRODUCT_KEY
							  andSecret:JW_OPEN_FEINT_SECRET
						 andDisplayName:@"KotH"
							andSettings:settings
						   andDelegates:nil];
	
	[OpenFeint respondToApplicationLaunchOptions:launchOptions];
	
	menuState = IPM_GAME;
	
	application.statusBarHidden = YES;
	application.statusBarOrientation = UIInterfaceOrientationLandscapeLeft;
	
	// get the documents directory, where we will write configs and save games
	NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
	NSString *documentsDirectory = [paths objectAtIndex:0];
	[documentsDirectory getCString: iphoneDocDirectory 
							maxLength: sizeof( iphoneDocDirectory ) - 1
							encoding: NSASCIIStringEncoding ];
	
	// get the app directory, where our data files live
	paths = NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSUserDomainMask, YES);
	NSString *appDirectory = documentsDirectory = [paths objectAtIndex:0];
	[appDirectory getCString: iphoneAppDirectory 
							maxLength: sizeof( iphoneAppDirectory ) - 1
							encoding: NSASCIIStringEncoding ];
	
	// start the flow of accelerometer events
	//UIAccelerometer *accelerometer = [UIAccelerometer sharedAccelerometer];
	//accelerometer.delegate = self;
	//accelerometer.updateInterval = 0.01;

	// Sort out buttons.
	[self hideTitleScreen:NO];
	[self hideLevelSelectScreen:YES];
	[self hideGameScreen:YES];
	enterGame.hidden = YES;
	
	[self positionLevelSelectUI];
	[self positionGameUI];
	[self positionTitleScreenUI];
	
	// do all the game startup work
	iphoneStartup();
	
	controlTest = NO;
	
	BOOL muted = NO;
	NSNumber* muteFromDefaults = [[NSUserDefaults standardUserDefaults] objectForKey:@"mute"];
	if(muteFromDefaults) {
		muted = [muteFromDefaults boolValue];
	}
	[self muteSounds:muted];
	
	// !!!! Comment this out when we're ready to ship!
	//maxLevel = 200;
	return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application 
{
	[OpenFeint applicationWillResignActive];
}


- (void)applicationDidBecomeActive:(UIApplication *)application 
{
	[OpenFeint applicationDidBecomeActive];
}

- (void)applicationWillTerminate:(UIApplication *)application {
	iphoneShutdown();
	[OpenFeint shutdown];
}

- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
	// wolf3d:foo should launch wolf3d now... next, add useful URL parameter encoding
	return YES;
}


- (void)dealloc {
	[window release];
	[glView release];
	[super dealloc];
}

/*
- (void)restartAccelerometerIfNeeded {

	// I have no idea why this seems to happen sometimes...
	if ( Sys_Milliseconds() - lastAccelUpdateMsec > 1000 ) {
		static int count;
		if ( ++count < 100 ) {
			printf( "Restarting accelerometer updates.\n" );
		}
		UIAccelerometer *accelerometer = [UIAccelerometer sharedAccelerometer];
		accelerometer.delegate = self;
		accelerometer.updateInterval = 0.01;
	}
}

- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{	
	float acc[4];
	acc[0] = acceleration.x;
	acc[1] = acceleration.y;
	acc[2] = acceleration.z;
	acc[3] = acceleration.timestamp;
	iphoneTiltEvent( acc );
	lastAccelUpdateMsec = Sys_Milliseconds();
}
*/

#pragma mark Title screen buttons.
-(IBAction)resume:(id)sender
{
	menuState = IPM_INTERMISSION;
	[self hideTitleScreen:YES];
	[self hideLevelSelectScreen:YES];
	[self hideGameScreen:YES];
	
	[self setLevelText];
	
	levelLabel.hidden = NO;
	dimensionLabel.hidden = NO;
	enterGame.hidden = NO;
	
	// If sender is nil, then we got here from finishing the level.
	// That's not treated as a resumption.
	resuming = !!sender;
}

-(IBAction)about:(id)sender
{
	JWAboutScreen* aboutScreen = [[JWAboutScreen alloc] initWithNibName:nil bundle:nil];
	
	// Warning - this is a private (OF-private not Apple-private!) method, but using it saves me writing my own stuff ;).
	[OpenFeint presentRootControllerWithModal:(UIViewController*)aboutScreen];
	//[[OpenFeint class] performSelector:@selector(presentRootControllerWithModal) withObject:aboutScreen];
	
	[aboutScreen release];
	
}

-(IBAction)help:(id)sender
{
	JWHelpScreen* helpScreen = [[JWHelpScreen alloc] initWithNibName:nil bundle:nil];
	
	// Warning - this is a private (OF-private not Apple-private!) method, but using it saves me writing my own stuff ;).
	[OpenFeint presentRootControllerWithModal:(UIViewController*)helpScreen];
	//[[OpenFeint class] performSelector:@selector(presentRootControllerWithModal) withObject:helpScreen];
	
	[helpScreen release];
	
}

-(IBAction)controls:(id)sender
{
	JWConfigureControls* configureControls = [[JWConfigureControls alloc] initWithNibName:nil bundle:nil];
	
	// Warning - this is a private (OF-private not Apple-private!) method, but using it saves me writing my own stuff ;).
	[OpenFeint presentRootControllerWithModal:(UIViewController*)configureControls];
	//[[OpenFeint class] performSelector:@selector(presentRootControllerWithModal) withObject:helpScreen];
	
	controlTest = NO;
	[configureControls release];
}

-(IBAction)chooseLevel:(id)sender
{	
	// Create a new level, same as the old one. This clears any existing stuff the player has done.
	JWLandscapeManager* landscapeManager = (JWLandscapeManager*)[[JWManagers sharedManager] managerOfClass:[JWLandscapeManager class]];
	JWLandscape* landscape = (JWLandscape*)[landscapeManager entity];
	[self newLevel:landscape.level];
	[self setLevelText];
	
	// And enter level select state.
	Player.health = 10;
	menuState = IPM_INTERMISSION;
	[self hideTitleScreen:YES];
	[self hideLevelSelectScreen:NO];
	[self hideGameScreen:YES];
	enterGame.hidden = NO;
	
	[self setLevelText];
}

-(IBAction)mute:(id)sender
{
	JWSound* soundMan = [JWSound soundManager];
	BOOL muted = ![soundMan muted];
	[self muteSounds:muted];
}

-(IBAction)dashboard:(id)sender
{
	[OpenFeint launchDashboard];
}

#pragma mark Back button.
-(IBAction)back:(id)sender
{
	if(controlTest) {
		[self controls:nil];
	}
	
	menuState = IPM_MAIN;
	[self hideTitleScreen:NO];
	[self hideLevelSelectScreen:YES];
	[self hideGameScreen:YES];
	enterGame.hidden = NO;
	
	resuming = NO;
	
	[glView resignFirstResponder];
}

#pragma mark Intermission button
-(IBAction)enterGame:(id)sender
{
	menuState = IPM_GAME;
	
	if(!controlTest) {
		[self hideTitleScreen:YES];
		[self hideLevelSelectScreen:YES];
		[self hideGameScreen:NO];
		Player.position.azimuth = -10;
		[self updateHealthDisplay];
	} else {
		[self hideAllExceptBack];
	}
	
	// Sentinels won't harm the player until the player absorbs or creates something.
	// If we're resuming, then the sentinels do whatever they were doing beforehand.
	if(!resuming || controlTest) {
		[JWSentinel resting:YES];
		if(resuming) {
			resuming = NO;
		}
	}
	
	enterGame.hidden = YES;
	[glView becomeFirstResponder];
}

#pragma mark Level select
-(IBAction)previous:(id)sender
{
	JWLandscapeManager* landscapeManager = (JWLandscapeManager*)[[JWManagers sharedManager] managerOfClass:[JWLandscapeManager class]];
	JWLandscape* landscape = (JWLandscape*)[landscapeManager entity];
	
	NSUInteger newLevel = landscape.level - 1;
	if(!newLevel) {
		newLevel = 1;
	}
	
	[self newLevel:newLevel];
}

-(IBAction)next:(id)sender
{
	JWLandscapeManager* landscapeManager = (JWLandscapeManager*)[[JWManagers sharedManager] managerOfClass:[JWLandscapeManager class]];
	JWLandscape* landscape = (JWLandscape*)[landscapeManager entity];
	
	NSUInteger newLevel = landscape.level + 1;
	if(newLevel > maxLevel) {
		newLevel = maxLevel;
	}
	
	[self newLevel:newLevel];
}

-(IBAction)levelSelect:(id)sender
{	
	// Register for keyboard appearance notification.
	[[NSNotificationCenter defaultCenter] addObserver:self 
											 selector:@selector(keyboardWillShow:) 
												 name:UIKeyboardWillShowNotification 
											   object:nil];
	
	// Open level selector view.
	textField = [UITextField alloc];
	[textField initWithFrame:CGRectMake( 0, 0, 20, 20 ) ];
	
	textField.clearsOnBeginEditing = YES;
	textField.keyboardType = UIKeyboardTypeNumberPad;
	textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
	textField.autocorrectionType = UITextAutocorrectionTypeNo;
	
	[glView addSubview:textField];
	[textField release];
	
	textField.hidden = true;
	textField.delegate = self;

	[textField becomeFirstResponder];

}

-(void)doneButton:(id)sender
{
	NSUInteger typedLevel = [textField.text integerValue];
	if(!typedLevel) {
		typedLevel = 1;
	}
	if(typedLevel > maxLevel) {
		typedLevel = maxLevel;
	}
	
	[textField resignFirstResponder];
	[self newLevel:typedLevel];
}

#pragma mark In-game Buttons
-(IBAction)teleport:(id)sender
{
	JWManagers* managers = [JWManagers sharedManager];
	JWLandscapeManager* landscapeManager = (JWLandscapeManager*)[managers managerOfClass:[JWLandscapeManager class]];
	JWLandscape* landscape = (JWLandscape*)[landscapeManager entity];
	JWSquare* square = [landscape selectedSquare];
	
	if(square.robot) {
		[[JWSound soundManager] playSound:@"teleport"];
		
		// Finished the level!
		if(square == landscape.highSquare) {

			[self updateOpenFeintWithCompletedLandscape:landscape];
			[self incrementLevel:Player.health];
			
			// Sets menuState to IPM_INTERMISSION and hides/reveals the appropriate buttons.
			[self resume:nil];
		} else {
			JWSquare* playerSquare = [landscape getSquareAtX:Player.position.origin[0] z:-Player.position.origin[1]];
			assert(playerSquare.player);
			playerSquare.player = NO;
			square.player = YES;
			
			JWRobot* r = [[[JWRobot alloc] initWithSquare:playerSquare] autorelease];
			[[JWAnimator animator] setTargetX:square.x y:[square height] + [square.boxes count] + 1.0f z:square.z];
			[[JWAnimator animator] addOnArrival:r];
		}
	}
}

-(IBAction)absorb:(id)sender
{
	// Don't let dead players resurrect themselves!
	if(Player.health >= 0 && Player.canAbsorb == YES) {
		JWLandscapeManager* landscapeManager = (JWLandscapeManager*)[[JWManagers sharedManager] managerOfClass:[JWLandscapeManager class]];
		JWLandscape* landscape = (JWLandscape*)[landscapeManager entity];
		JWSquare* square = landscape.selectedSquare;

		// Can't absorb stuff on the square we're standing on.
		// Except if it's the robot we're teleporting to. sender will be nil in this case.
		if(!square.player || !sender) {
			NSObject<JWEntity>* item = nil;
			if(square.selected) {
				if(square.tree) {
					item = square.tree;
				} else if(square.robot) {
					item = square.robot;
				} else if(square.sentinel) {
					item = square.sentinel;
					if(square.sentinel.sentinelId == 0) {
						// No more absorbing once we've got the boss.
						Player.canAbsorb = NO;
						// The boss is worth one more point than a normal sentinel.
						Player.health++;
					}
				} else if([square boxCount]) {
					item = [square topBox];
				}
			}

			if(item) {
				// Don't play sound if we're teleporting to a robot.
				if(sender) {
					[[JWSound soundManager] playSound:@"absorb"];
				}
				
				NSObject<JWManager>* manager = [item manager];
				Player.health += [[item class] energy];
				[self updateHealthDisplay];
				[JWSentinel resting:NO];
				[manager removeEntity:item];
				
				if(square.endOfLevel) {
					// Automatically stick a robot on the final square.
					[self robot:sender];
				}
			}
		}
	}
}

-(IBAction)box:(id)sender
{
	if(Player.health >= [JWBox energy]) {
		JWLandscapeManager* landscapeManager = (JWLandscapeManager*)[[JWManagers sharedManager] managerOfClass:[JWLandscapeManager class]];
		JWLandscape* landscape = (JWLandscape*)[landscapeManager entity];
		JWSquare* square = [landscape selectedSquare];
		
		if([square canMoveTo]) {
		   // Box will be retained by the square's box list.
		   JWBox* b = [[[JWBox alloc] initWithSquare:square] autorelease];
			b.selected = YES;
		   [self addEntity:b];
		}
	}
}

-(IBAction)robot:(id)sender
{
	if(Player.health >= [JWRobot energy]) {
		JWLandscapeManager* landscapeManager = (JWLandscapeManager*)[[JWManagers sharedManager] managerOfClass:[JWLandscapeManager class]];
		JWLandscape* landscape = (JWLandscape*)[landscapeManager entity];
		JWSquare* square = [landscape selectedSquare];
		
		if([square canMoveTo]) {
			// Box will be retained by the square's box list.
			JWRobot* r = [[[JWRobot alloc] initWithSquare:square] autorelease];
			r.selected = YES;
			[self addEntity:r];
		}
	}
}

-(IBAction)tree:(id)sender
{
	if(Player.health >= [JWTree energy]) {
		JWLandscapeManager* landscapeManager = (JWLandscapeManager*)[[JWManagers sharedManager] managerOfClass:[JWLandscapeManager class]];
		JWLandscape* landscape = (JWLandscape*)[landscapeManager entity];
		JWSquare* square = [landscape selectedSquare];
		
		if([square canMoveTo]) {
			// Box will be retained by the square's box list.
			JWTree* t = [[[JWTree alloc] initWithSquare:square] autorelease];
			t.selected = YES;
			[self addEntity:t];
		}
	}
}

-(IBAction)uturn:(id)sender
{
	[[JWAnimator animator] uturn];
}

-(void)emergencyTeleportCanDie:(BOOL)canDie
{
	if(menuState == IPM_GAME && ![JWAnimator animator].animationFrames) {
		if(canDie && Player.health <= [JWRobot energy]) {
			Player.health = -1;
		} else {
			// Ask landscape for squares lower than player.
			JWLandscapeManager* landscapeManager = (JWLandscapeManager*)[[JWManagers sharedManager] managerOfClass:[JWLandscapeManager class]];
			JWLandscape* landscape = (JWLandscape*)[landscapeManager entity];
			NSArray* lowSquares = [landscape getSquaresLowerThanHeight:rint(Player.position.height)];
			
			// Choose one at random.
			NSUInteger index = randomInt([lowSquares count]);
			JWSquare* destination = [lowSquares objectAtIndex:index];
			
			// Jump there, leaving a robot, and hence three units of energy, at the old position.
			landscape.selectedSquare.selected = NO;
			destination.selected = YES;
			landscape.selectedSquare = destination;
			[self robot:nil];
			[self teleport:nil];	
			[JWSentinel resting:NO];
		}
	}
}

#pragma mark Hiding stuff.
-(void)hideTitleScreen:(BOOL)hide
{
	titleScreen.hidden = hide;
	play.hidden = hide;
	resume.hidden = hide;
	about.hidden = hide;
	help.hidden = hide;
	controls.hidden = hide;
	chooseLevel.hidden = hide;
	mute.hidden = hide;
	dashboard.hidden = hide;
	backButton.hidden = !hide;
}

-(void)hideLevelSelectScreen:(BOOL)hide
{
	[self hidePreviousNext:hide];
	levelLabel.hidden = hide;
	levelLabelButton.hidden = hide;
	dimensionLabel.hidden = hide;
}

-(void)hideGameScreen:(BOOL)hide
{
	teleport.hidden = hide;
	absorb.hidden = hide;
	box.hidden = hide;
	robot.hidden = hide;
	tree.hidden = hide;
	uturn.hidden = hide;
	
	energyLabel.hidden = hide;
}

-(void)hideAllExceptBack
{
	[self hideTitleScreen:YES];
	[self hideLevelSelectScreen:YES];
	[self hideGameScreen:YES];
	backButton.hidden = NO;
}

-(void)hidePreviousNext:(BOOL)hide
{
	BOOL hidePrevious = hide;
	BOOL hideNext = hide;
	if(hide == NO) {
		JWLandscapeManager* landscapeManager = (JWLandscapeManager*)[[JWManagers sharedManager] managerOfClass:[JWLandscapeManager class]];
		JWLandscape* landscape = (JWLandscape*)[landscapeManager entity];
		
		if(landscape.level == 1) {
			hidePrevious = YES;
		}
		
		if(landscape.level == maxLevel) {
			hideNext = YES;
		}
	}
	previous.hidden = hidePrevious;
	next.hidden = hideNext;
}



#pragma mark Postion stuff.
-(void)positionLevelSelectUI
{	
	static double margin = 20.0;
	static double separation = 10.0;
	
	// Next button.
	CGRect frame = next.frame;
	frame.origin.x = margin;
	frame.origin.y = margin;
	frame.size.width = 35.0;
	frame.size.height = 50.0;
	next.frame = frame;
	
	// Back button.
	frame.origin.x = margin;
	frame.origin.y = window.frame.size.height - frame.size.height - margin;
	backButton.frame = frame;
	
	// Previous button.
	frame.origin.x = margin;
	frame.origin.y = window.frame.size.height - 2.0 * frame.size.height - margin - separation;
	previous.frame = frame;
	
	// Level button.
	frame.origin.x = margin;
	frame.origin.y = margin + next.frame.size.height + separation;
	frame.size.height = window.frame.size.height - (3.0 * (next.frame.size.height + separation)) - (2.0 * margin);
	levelLabelButton.frame = frame;
	
	// Level label.
	frame.size.height = levelLabelButton.frame.size.width;
	levelLabel.frame = frame;
	levelLabel.center = levelLabelButton.center;
	levelLabel.textAlignment = UITextAlignmentCenter;
	
	// Dimension label.
	frame = dimensionLabel.frame;
	frame.size.width = 100.0;
	frame.size.height = 35.0;
	dimensionLabel.frame = frame;
	CGPoint centre;
	centre.x = window.frame.size.width - margin - frame.size.height / 2.0;
	centre.y = window.frame.size.height - margin - frame.size.width / 2.0;
	dimensionLabel.center = centre;
	dimensionLabel.textAlignment = UITextAlignmentLeft;
	
	// Rotate the level and dimension labels.
	CGAffineTransform rotateTransform = CGAffineTransformRotate(CGAffineTransformIdentity, -M_PI / 2.0f);
	levelLabel.transform = rotateTransform;
	dimensionLabel.transform = rotateTransform;
}

-(void)positionGameUI
{
	static double margin = 20.0;
	static double separation = 10.0;
	
	// Absorb.
	CGRect frame = absorb.frame;
	frame.size.width = 48.0;
	frame.size.height = 48.0;
	frame.origin.x = window.frame.size.width - margin - frame.size.width;
	frame.origin.y = window.frame.size.height - margin - frame.size.height;
	absorb.frame = frame;
	
	// Tree.
	frame.origin.y -= frame.size.height + 2.0f * separation;
	tree.frame = frame;
	
	// Box.
	frame.origin.y -= frame.size.height + separation;
	box.frame = frame;
	
	// Robot.
	frame.origin.y -= frame.size.height + separation;
	robot.frame = frame;
	
	// Teleport.
	frame.origin.y -= frame.size.height + 2.0f * separation;
	teleport.frame = frame;
	
	// Uturn.
	frame.origin.y -= frame.size.height + separation;
	uturn.frame = frame;
	
	// Energy label.
	frame.size.width = 100.0;
	frame.size.height = 35.0;
	CGPoint centre;
	centre.x = margin + frame.size.height / 2.0;
	centre.y = margin + frame.size.width / 2.0;
	energyLabel.center = centre;
	energyLabel.textAlignment = UITextAlignmentRight;

	CGAffineTransform rotateTransform = CGAffineTransformRotate(CGAffineTransformIdentity, -M_PI / 2.0f);
	energyLabel.transform = rotateTransform;
}

-(void)positionTitleScreenUI
{
	static double margin = 20.0;
	static double separation = 10.0;
	
	CGRect frame;
	frame.size.width = 220.0;
	frame.size.height = 40.0;
	chooseLevel.frame = frame;
	resume.frame = frame;
	controls.frame = frame;
	help.frame = frame;
	about.frame = frame;
	
	// New Game.
	CGPoint centre;
	centre.x = margin + frame.size.height / 2.0;
	centre.y = window.frame.size.height - margin - frame.size.width / 2.0;
	chooseLevel.center = centre;
	
	// Resume.
	centre.x += separation + frame.size.height;
	resume.center = centre;
	
	// Controls.
	centre.x += separation + frame.size.height;
	controls.center = centre;	

	// Help.
	centre.x += separation + frame.size.height;
	help.center = centre;
	
	// About.
	centre.x += separation + frame.size.height;
	about.center = centre;
	
	CGAffineTransform rotateTransform = CGAffineTransformRotate(CGAffineTransformIdentity, -M_PI / 2.0f);
	chooseLevel.transform = rotateTransform;
	resume.transform = rotateTransform;
	controls.transform = rotateTransform;
	help.transform = rotateTransform;
	about.transform = rotateTransform;
	mute.transform = rotateTransform;
}

#pragma mark Utility stuff.
-(void)addEntity:(NSObject<JWEntity>*)entity
{						
	NSObject<JWManager>* manager = [entity manager];
	[manager addEntity:entity];
	Player.health = Player.health - [[entity class] energy];
	[self updateHealthDisplay];
	[JWSentinel resting:NO];
	[[JWSound soundManager] playSound:@"create"];
}

-(void)incrementLevel
{
	[self incrementLevel:1];
}

-(void)incrementLevel:(NSUInteger)amount
{
	JWLandscapeManager* landscapeManager = (JWLandscapeManager*)[[JWManagers sharedManager] managerOfClass:[JWLandscapeManager class]];
	JWLandscape* landscape = (JWLandscape*)[landscapeManager entity];
	[self newLevel:landscape.level + amount];
}

-(void)decrementLevel
{
	JWLandscapeManager* landscapeManager = (JWLandscapeManager*)[[JWManagers sharedManager] managerOfClass:[JWLandscapeManager class]];
	JWLandscape* landscape = (JWLandscape*)[landscapeManager entity];
	[self newLevel:landscape.level - 1];
}

-(void)newLevel:(NSUInteger)level
{
	if(level > maxLevel) {
		maxLevel = level;
	}
	
	NSEnumerator* enumerator = [[[JWManagers sharedManager] managers] objectEnumerator];
	NSObject<JWManager>* m = nil;
	
	while(m = [enumerator nextObject]) {
		[m removeAllEntities];
	}
	
	JWLandscapeManager* landscapeManager = (JWLandscapeManager*)[[JWManagers sharedManager] managerOfClass:[JWLandscapeManager class]];
	JWLandscape* landscape = [[[JWLandscape alloc] initWithLevel:level populate:YES] autorelease];
	[landscapeManager addEntity:landscape];
	[[JWPicker picker] changeLandscape:landscape];
	
	Player.canAbsorb = YES;
	
	[self setLevelText];
	[self hidePreviousNext:NO];
}

-(void)setLevelText
{
	JWLandscapeManager* landscapeManager = (JWLandscapeManager*)[[JWManagers sharedManager] managerOfClass:[JWLandscapeManager class]];
	JWLandscape* landscape = (JWLandscape*)[landscapeManager entity];
	
	levelLabel.text = [NSString stringWithFormat:@"%u", landscape.level];
	dimensionLabel.text = [NSString stringWithFormat:@"%u x %u", landscape.maxX , landscape.maxZ];
}

-(void)updateHealthDisplay
{
	if(Player.health >= 0) {
		energyLabel.text = [NSString stringWithFormat:@"%d", Player.health];
	} else {
		energyLabel.text = @"Dead";
	}
}

-(void)updateOpenFeintWithCompletedLandscape:(JWLandscape*)landscape
{
	// Finished the last unlocked level - update leaderboard.
	if(landscape.level == maxLevel) {
		[OFHighScoreService setHighScore:maxLevel forLeaderboard:@"101484" onSuccess:OFDelegate() onFailure:OFDelegate()];
	}
	
	// Award achievements.
	if(landscape.level >= 1)		[OFAchievementService unlockAchievement:@"117104"];
	if(landscape.level >= 10)		[OFAchievementService unlockAchievement:@"117114"];
	if(landscape.level >= 100)		[OFAchievementService unlockAchievement:@"117124"];
	if(landscape.level >= 1000)		[OFAchievementService unlockAchievement:@"117134"];
	if(landscape.level >= 10000)	[OFAchievementService unlockAchievement:@"117144"];
	if(landscape.level >= 100000)	[OFAchievementService unlockAchievement:@"117154"];
}

-(void)playerDied
{
	[[JWSound soundManager] stopAllSounds];
	
	JWLandscapeManager* landscapeManager = (JWLandscapeManager*)[[JWManagers sharedManager] managerOfClass:[JWLandscapeManager class]];
	JWLandscape* landscape = (JWLandscape*)[landscapeManager entity];
	
	menuState = IPM_INTERMISSION;
	Player.health = 10;
	[self newLevel:landscape.level];
	[self resume:nil];
}


// http://www.neoos.ch/news/46-development/54-uikeyboardtypenumberpad-and-the-missing-return-key
- (void)keyboardWillShow:(NSNotification*)note 
{
    // create custom button
    UIButton *doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
    doneButton.frame = CGRectMake(0, 123, 158, 39);
    doneButton.adjustsImageWhenHighlighted = NO;
    [doneButton setImage:[UIImage imageNamed:@"DoneUp3Land.png"] forState:UIControlStateNormal];
    [doneButton setImage:[UIImage imageNamed:@"Done3Land.png"] forState:UIControlStateHighlighted];
    [doneButton addTarget:self action:@selector(doneButton:) forControlEvents:UIControlEventTouchUpInside];
	
    // locate keyboard view
    UIWindow* tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:1];
    UIView* keyboard;
    for(int i=0; i<[tempWindow.subviews count]; i++) {
        keyboard = [tempWindow.subviews objectAtIndex:i];
        // keyboard view found; add the custom button to it
        if([[keyboard description] hasPrefix:@"<UIKeyboard"] == YES)
            [keyboard addSubview:doneButton];
    }
	[[NSNotificationCenter defaultCenter] removeObserver:self];
}

#pragma mark UITextFieldDelegate methods
-(BOOL)textField:(UITextField*)textField_ shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString*)string
{
	if(textField_ == textField) {
		NSString* text = textField.text;
		NSString* newText = [text stringByReplacingCharactersInRange:range withString:string];
		levelLabel.text = newText;
		dimensionLabel.text = @"";
	}
	return YES;
}

-(void)tryControls
{
	controlTest = YES;
	[self newLevel:1];
	[self enterGame:nil];
}

-(void)muteSounds:(BOOL)aMute
{
	[[JWSound soundManager] muteSounds:aMute];
	
	NSString* path = nil;
	if(aMute) {
		path = [[NSBundle mainBundle] pathForResource:@"SoundOff" ofType:@"png"];
	} else {
		path = [[NSBundle mainBundle] pathForResource:@"SoundOn" ofType:@"png"];
	}
	assert(path);
	
	UIImage* image = [UIImage imageWithContentsOfFile:path];
	[mute setImage:image forState:UIControlStateNormal];
	
	NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
	[defaults setObject:[NSNumber numberWithBool:aMute] forKey:@"mute"];
	[defaults synchronize];
}

@end



